import 'dart:async';
import 'dart:io';

import 'package:annotation_route/route.dart';
import 'package:dk_flutter_base/dk_core.dart';
import 'package:dk_flutter_base/dk_ui.dart';
import 'package:flutter/services.dart';
import 'package:flutter_boost/flutter_boost.dart';

typedef RouteResultCallback(Map<String, dynamic> resultMap);
typedef void PageResultHandler(String key, Map<dynamic, dynamic> result);
typedef MayPopResult(bool mapPop);

/// Navigator 继承自 StatefulWidget，它也是小组件，它有很多相关静态函数，可以帮我们达到页面跳转和数据交互的功能：
/// 所有弹出窗口所使用的context不能是顶层Widget的context，同时顶层Widget必须是StatefulWidget。参考：https://www.jianshu.com/p/4c099e8c03c0
//
//push 将设置的router信息推送到Navigator上，实现页面跳转。
//of 主要是获取 Navigator最近实例的好状态。
//pop 导航到新页面，或者返回到上个页面。
//canPop 判断是否可以导航到新页面
//maybePop 可能会导航到新页面
//popAndPushNamed 指定一个路由路径，并导航到新页面。
//popUntil 反复执行pop 直到该函数的参数predicate返回true为止。
//pushAndRemoveUntil 将给定路由推送到Navigator，删除先前的路由，直到该函数的参数predicate返回true为止。
//pushNamed 将命名路由推送到Navigator。
//pushNamedAndRemoveUntil 将命名路由推送到Navigator，删除先前的路由，直到该函数的参数predicate返回true为止。
//pushReplacement 路由替换。
//pushReplacementNamed 这个也是替换路由操作。推送一个命名路由到Navigator，新路由完成动画之后处理上一个路由。
//removeRoute 从Navigator中删除路由，同时执行Route.dispose操作。
//removeRouteBelow 从Navigator中删除路由，同时执行Route.dispose操作，要替换的路由是传入参数anchorRouter里面的路由。
//replace 将Navigator中的路由替换成一个新路由。
//replaceRouteBelow 将Navigator中的路由替换成一个新路由，要替换的路由是是传入参数anchorRouter里面的路由。
///
class RouteUtil {
  ///Flutter跳转路由-压栈
  static pushByRoute(
      BuildContext context, PageRoute<Map<String, dynamic>> pageRoute,
      {Map<String, dynamic> popResult,
      RoutePredicate predicate,
      RouteResultCallback resultCallBack,
      PushType pushType}) {
    if (null == context) {
      return;
    }
    pushType ??= PushType.normal;
    Future<Map<String, dynamic>> future;
    switch (pushType) {
      case PushType.normal:
        future = Navigator.push(context, pageRoute);
        break;
      case PushType.replaceInStack:
        future = Navigator.pushReplacement(context, pageRoute);
        break;
      case PushType.popLast:
        Navigator.pop(context, popResult);
        future = Navigator.push(context, pageRoute);
        break;
      case PushType.removeAll:
        future = Navigator.pushAndRemoveUntil(
            context, pageRoute, (Route<dynamic> route) => false);
        break;
      case PushType.removeUntil:
        if (null == predicate) {
          predicate = (Route<dynamic> route) => true;
        }
        future = Navigator.pushAndRemoveUntil(context, pageRoute, predicate);
        break;
    }
    if (null != resultCallBack) {
      future.then(resultCallBack);
    }
  }

  ///Flutter跳转路由-压栈
  static push(BuildContext context,
      {WidgetBuilder targetWidgetBuilder,
      String widgetRoute,
      Map<String, dynamic> widgetParams,
      Map<String, dynamic> popResult,
      RoutePredicate predicate,
      RouteResultCallback resultCallBack,
      PushType pushType}) {
    pushType ??= PushType.normal;
    PageRoute pageRoute = MaterialPageRoute<Map<String, dynamic>>(
        builder: targetWidgetBuilder ??
            (BuildContext buildContext) {
              return getWidget(widgetRoute, widgetParams: widgetParams);
            });
    pushByRoute(context, pageRoute,
        popResult: popResult,
        predicate: predicate,
        resultCallBack: resultCallBack,
        pushType: pushType);
  }

  ///Flutter跳转路由-出栈
  static pop(BuildContext context,
      {Map<String, dynamic> result,
      PopType popType,
      RoutePredicate predicate,
      MayPopResult mayPopResult}) async {
    if (null == context) {
      return;
    }
    popType = PopType.normal;
    switch (popType) {
      case PopType.normal:
        if (Navigator.of(context).canPop()) {
          Navigator.of(context).pop(result);
        } else {
          popApp();
        }
        break;
      case PopType.popOnly:
        Navigator.of(context).pop(result);
        break;
      case PopType.check:
        mayPopResult(await Navigator.of(context).maybePop(result));
        break;
      case PopType.continueUntil:
        if (null == predicate) {
          predicate = (Route<dynamic> route) => true;
        }
        Navigator.of(context).popUntil(predicate);
        break;
    }
  }

  static bool canPop(BuildContext context) {
    if (null == context) {
      return false;
    }
    return Navigator.of(context).canPop();
  }

  ///Flutter跳转路由-退出Flutter
  static popApp() async {
    await SystemNavigator.pop();
  }

  ///Flutter跳转路由-强制退出应用
  static forcePopApp() async {
    exit(0);
  }

  ///Flutter-Widget路由-通过路由获取widget
  static Widget getWidget(String widgetRoute,
      {Map<String, dynamic> widgetParams}) {
    return getWidgetByOption(WidgetOption(widgetRoute, widgetParams));
  }

  ///Flutter-Widget路由-通过路由获取widget
  static Widget getWidgetByOption(WidgetOption widgetOption) {
    if (null == widgetOption || stringBlank(widgetOption?.widgetRoute)) {
      return Env.value.defaultPageBuilder('')??LogicPage.emptyPage();
    }
    ARouterResult routeResult = Env.value?.routeIml
        ?.findPage(ARouteOption(widgetOption.widgetRoute, null), widgetOption);
    if (routeResult.state == ARouterResultState.FOUND) {
      return routeResult.widget;
    }
    return Env.value.defaultPageBuilder(widgetOption.widgetRoute)??LogicPage.emptyPage();
  }

  ///Flutter-Boost路由-通过路由获取page
  static Widget getBoostPage(String pageName, {Map params, String uniqueId}) {
    return getBoostPageByOption(BoostRouteOption(pageName, params, uniqueId));
  }

  ///Flutter-Boost路由-通过路由获取page
  static Widget getBoostPageByOption(BoostRouteOption boostRouteOption) {
    if (null == boostRouteOption || stringBlank(boostRouteOption?.pageName)) {
      return LogicPage.emptyPage();
    }
    ARouterResult routeResult = Env.value?.routeIml?.findPage(
        ARouteOption(boostRouteOption.pageName, null), boostRouteOption);
    if (routeResult.state == ARouterResultState.FOUND) {
      return routeResult.widget;
    }
    return LogicPage.emptyPage();
  }

  ///Flutter-Boost-跳转Native指定界面
  static goPage(
    String nativeRoute, {
    Map params,
    bool animated,
    PageResultHandler resultHandler,
    BuildContext widgetContext,
    Map<String, dynamic> widgetParams,
    RouteResultCallback widgetResultCallback,
  }) {
    if (stringBlank(nativeRoute)) {
      return;
    }
    if (nativeRoute
        .startsWith(Env.value?.schemeFlutterFilterName ?? "dkwidget://")) {
      Uri uri = Uri.tryParse(nativeRoute);
      if (objEmpty(uri)) {
        return;
      }
      StringBuffer sb = StringBuffer();
      sb.write(Env.value?.schemeFlutterFilterName ?? "dkwidget://");
      sb.write(uri.host);
      sb.write(uri.path);

      Map<String, dynamic> paramsMap = Map<String, dynamic>();
      if (mapNotEmpty(uri.queryParameters)) {
        paramsMap.addAll(uri.queryParameters);
      }
      if (mapNotEmpty(widgetParams)) {
        paramsMap.addAll(widgetParams);
      }
      push(widgetContext,
          widgetRoute: sb.toString(),
          widgetParams: paramsMap,
          resultCallBack: widgetResultCallback);
      return;
    }
    FlutterBoost.singleton.openPage(nativeRoute, params,
        animated: animated, resultHandler: resultHandler);
  }

  ///Flutter-Boost-根据context关闭界面
  static Future<bool> closePageForContext(BuildContext context) {
    return FlutterBoost.singleton.closePageForContext(context);
  }

  ///Flutter-Boost-可传参数params[animated] = bool
  static Future<bool> closeCurrentPage(Map params) {
    return FlutterBoost.singleton.closeCurPage(params);
  }

  ///Flutter-Boost-关闭界面
  static Future<bool> closePage(String url, String pageId, Map params,
      {bool animated}) {
    return FlutterBoost.singleton
        .closePage(url, pageId, params, animated: animated);
  }

  ///Flutter-Boost-设置返回结果
  static bool setPageResult(BuildContext context, Map resultData,
      {Map params}) {
    BoostContainerSettings settings = BoostContainer.of(context).settings;
    if (settings.params.containsKey("result_id")) {
      String rid = settings.params["result_id"];
      return FlutterBoost.singleton.onPageResult(rid, resultData, params ?? {});
    }
    return false;
  }

  ///Flutter-Boost-设置FlutterPage返回结果
  static Future<bool> setBoostPageResultWithClose(
      BuildContext context, Map resultData,
      {Map params}) {
    if (setPageResult(context, resultData, params: params)) {
      return closePageForContext(context);
    }
    return Future<bool>(() {
      return false;
    });
  }

  /*///Flutter-Boost-设置WidgetPage返回结果
  static Future<bool> setWidgetPageResultWithClose(
      BuildContext context, Map resultData,
      {Map params}) {
    if (setPageResult(context, resultData, params: params)) {
      return pop(context);
    }
    return Future<bool>(() {
      return false;
    });
  }*/

  ///混合判断关闭界面
  static popOrCloseCurPage({bool animated = true, BuildContext context}) async {
    if (null != context && canPop(context)) {
      pop(context);
      return;
    }
    if (!await RouteUtil.closeCurrentPage({"animated": animated})) {
      popApp();
    }
  }

//todo 共享元素动画
}

enum PushType { normal, replaceInStack, popLast, removeUntil, removeAll }

enum PopType { normal, popOnly, check, continueUntil }

class WidgetOption {
  String widgetRoute;
  Map<String, dynamic> widgetParams;

  WidgetOption(this.widgetRoute, this.widgetParams);
}

class BoostRouteOption {
  String pageName;
  Map params;
  String uniqueId;

  BoostRouteOption(this.pageName, this.params, this.uniqueId);
}
